package com.ysh.smartplatform.event.listener;

import com.ysh.smartplatform.event.LoginFailEvent;
import com.ysh.smartplatform.event.LoginSuccessEvent;
import com.ysh.smartplatform.pojo.BaseUser;
import com.ysh.smartplatform.pojo.SysLogininfor;
import com.ysh.smartplatform.pojo.SysUserOnline;
import com.ysh.smartplatform.service.LoginLogService;
import com.ysh.smartplatform.service.OnLineUserService;
import com.ysh.smartplatform.service.UserService;
import com.ysh.smartplatform.utils.RequestUtil;
import com.ysh.smartplatform.utils.SecurityUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.event.EventListener;
import org.springframework.core.task.TaskExecutor;
import org.springframework.security.access.event.AuthorizationFailureEvent;
import org.springframework.security.authentication.event.AuthenticationSuccessEvent;
import org.springframework.security.core.userdetails.User;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.servlet.http.HttpServletRequest;
import java.util.Date;
import java.util.Map;
import java.util.concurrent.CompletableFuture;

/**
 * 袁胜虎 on 2022/9/5 21:06
 *定义的事件最后会在对应的servlet 方法中进行调用
 */
@Component//Component是一个元注解,意思是可以注解其他类注解
public class LoginEventListener {
    private TaskExecutor taskExecutor;

    @Autowired
    public void setTaskExecutor(TaskExecutor taskExecutor) {
        this.taskExecutor = taskExecutor;
    }

    private OnLineUserService onLineUserService;

    @Autowired
    public void setOnLineUserService(OnLineUserService onLineUserService) {
        this.onLineUserService = onLineUserService;
    }

    private LoginLogService loginLogService;

    @Autowired
    public void setLoginLogService(LoginLogService loginLogService) {
        this.loginLogService = loginLogService;
    }

    public UserService userService;

    @Autowired
    public void setUserService(UserService userService) {
        this.userService = userService;
    }

    //@Async//异步执行
    @EventListener//建立事件对象 当调用publishEvent方法是会通过这个bean对象找对应事件的监听
    public void onEvent(AuthenticationSuccessEvent event) throws InterruptedException{
        String username = ((BaseUser) event.getAuthentication().getPrincipal()).getUsername();
        Long userId =   ((BaseUser) event.getAuthentication().getPrincipal()).getuId();
        System.err.println(Thread.currentThread().getName());
        //获取到request
        HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
        //根据请求头user-agent获取用户的浏览器,操作系统
        Map<String, String> osAndBrowserInfo = RequestUtil.getOsAndBrowserInfo(request);
        String sessionId = request.getSession().getId();
        String ip = request.getRemoteHost();
        //异步执行
        CompletableFuture.runAsync(()->{
            //更新登录的时间和ip
            userService.updateLoginData(userId,ip);
        },taskExecutor);
        CompletableFuture.runAsync(()->{
//            //获取系统和浏览器的信息
//            String os = osAndBrowserInfo.get("os");
//            String browser = osAndBrowserInfo.get("browser");
//            System.err.println(os);
//            System.err.println(browser);
//            String locationByIp = RequestUtil.getLocationByIp(ip);
//            System.err.println(locationByIp);
            SysLogininfor sysLogininfor = addLog(osAndBrowserInfo, ip, username);
            sysLogininfor.setStatus(1L);
            sysLogininfor.setMsg("登录成功");
            //插入到登录日志表中
            loginLogService.addLog(sysLogininfor);

            //获取系统和浏览器的信息
            String os = osAndBrowserInfo.get("os");
            String browser = osAndBrowserInfo.get("browser");
            //TODO 将数据插入到数据库,注意,理论上一个用户名应该只有一行数据
            SysUserOnline sysUserOnline = new SysUserOnline();
            sysUserOnline.setSessionId(sessionId);
            sysUserOnline.setLoginName(username);
            sysLogininfor.setIpaddr(ip);
            //设置登录地址,用上面的登录日志中的数据来设置
            sysUserOnline.setLoginLocation(sysLogininfor.getLoginLocation());
            sysLogininfor.setBrowser(browser);
            sysUserOnline.setOs(os);
            sysUserOnline.setStatus("1");
            sysUserOnline.setStartTimestamp(new Date());
            sysUserOnline.setLastAccessTime(new Date());
            sysUserOnline.setExpireTime(30L);
            onLineUserService.addOnlineData(sysUserOnline);

        },taskExecutor);
    }

    @EventListener
    public void onLoginFail(AuthorizationFailureEvent event)throws InterruptedException{
        String username = null;
        if (event.getAuthentication().getPrincipal() instanceof BaseUser) {
            username = ((BaseUser) event.getAuthentication().getPrincipal()).getUsername();
        }
        if (username == null) {
            return;
        }
        //获取到request
        HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
        //根据请求头user-agent获取用户的浏览器,操作系统
        Map<String, String> osAndBrowserInfo = RequestUtil.getOsAndBrowserInfo(request);
        String ip = request.getRemoteHost();
        //在异步中添加数据
        String finalUsername = username;
        CompletableFuture.runAsync(()->{
            SysLogininfor sysLogininfor = addLog(osAndBrowserInfo, ip, finalUsername);
            sysLogininfor.setStatus(0L);
            sysLogininfor.setMsg("登录失败");
            //同时插入到登录日志表中
            loginLogService.addLog(sysLogininfor);
        },taskExecutor);
    }

    /**
     * 将数据封装到登录日志对象中
     * @param osAndBrowserInfo
     * @param ip
     * @param userName
     * @return
     */

    public SysLogininfor addLog(Map<String, String> osAndBrowserInfo, String ip,String userName){
        String os = osAndBrowserInfo.get("os");
        String browser = osAndBrowserInfo.get("browser");
        System.err.println(os);
        System.err.println(browser);
        //根据ip获取地址
//        String locationByIp = RequestUtil.getLocationByIp(ip);
        String locationByIp="局域网地址";
        SysLogininfor sysLogininfor = new SysLogininfor();
        sysLogininfor.setLoginName(userName);
        sysLogininfor.setIpaddr(ip);
        sysLogininfor.setLoginLocation(locationByIp);
        sysLogininfor.setBrowser(browser);
        sysLogininfor.setOs(os);
        sysLogininfor.setLoginTime(new Date());
        return sysLogininfor;
    }
}
